// 简化的TOTP实现，不依赖Web Crypto API

/**
 * 将 Base32 编码的字符串解码为 Uint8Array
 */
function base32ToUint8Array(base32) {
  const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
  base32 = base32.toUpperCase().replace(/=+$/, ''); // 去除填充符

  const bitsPerChar = 5;
  const output = new Uint8Array(Math.ceil((base32.length * bitsPerChar) / 8));

  let bitBuffer = 0;
  let bitsInBuffer = 0;
  let outputIndex = 0;

  for (let i = 0; i < base32.length; i++) {
    const charIndex = alphabet.indexOf(base32[i]);
    if (charIndex === -1) {
      throw new Error('Invalid Base32 character found: ' + base32[i]);
    }

    bitBuffer = (bitBuffer << bitsPerChar) | charIndex;
    bitsInBuffer += bitsPerChar;

    while (bitsInBuffer >= 8) {
      bitsInBuffer -= 8;
      output[outputIndex++] = (bitBuffer >> bitsInBuffer) & 0xFF;
    }
  }
  return output;
}

/**
 * 简单的HMAC-SHA1实现（不依赖Web Crypto API）
 */
function hmacSha1(key, message) {
  const blockSize = 64; // SHA-1 block size
  const keyBytes = new Uint8Array(key);
  const messageBytes = new Uint8Array(message);
  
  // 如果密钥长度大于块大小，先进行哈希
  let actualKey = keyBytes;
  if (keyBytes.length > blockSize) {
    actualKey = sha1(keyBytes);
  }
  
  // 如果密钥长度小于块大小，用零填充
  if (actualKey.length < blockSize) {
    const paddedKey = new Uint8Array(blockSize);
    paddedKey.set(actualKey);
    actualKey = paddedKey;
  }
  
  // 创建内部和外部填充
  const ipad = new Uint8Array(blockSize);
  const opad = new Uint8Array(blockSize);
  
  for (let i = 0; i < blockSize; i++) {
    ipad[i] = actualKey[i] ^ 0x36;
    opad[i] = actualKey[i] ^ 0x5c;
  }
  
  // 计算 HMAC
  const innerData = new Uint8Array(blockSize + messageBytes.length);
  innerData.set(ipad);
  innerData.set(messageBytes, blockSize);
  
  const innerHash = sha1(innerData);
  const outerData = new Uint8Array(blockSize + innerHash.length);
  outerData.set(opad);
  outerData.set(innerHash, blockSize);
  
  return sha1(outerData);
}

/**
 * 简单的SHA-1实现
 */
function sha1(data) {
  // 预处理
  const msg = new Uint8Array(data);
  const msgLength = msg.length;
  const bitLength = msgLength * 8;
  
  // 添加填充
  const paddedLength = Math.ceil((msgLength + 9) / 64) * 64;
  const padded = new Uint8Array(paddedLength);
  padded.set(msg);
  padded[msgLength] = 0x80;
  
  // 添加长度（64位大端序）
  const view = new DataView(padded.buffer);
  view.setUint32(paddedLength - 4, Math.floor(bitLength / 0x100000000), false);
  view.setUint32(paddedLength - 8, bitLength & 0xffffffff, false);
  
  // 初始化哈希值
  let h0 = 0x67452301;
  let h1 = 0xEFCDAB89;
  let h2 = 0x98BADCFE;
  let h3 = 0x10325476;
  let h4 = 0xC3D2E1F0;
  
  // 处理每个512位块
  for (let chunk = 0; chunk < paddedLength; chunk += 64) {
    const w = new Array(80);
    
    // 将块分解为16个32位字
    for (let i = 0; i < 16; i++) {
      w[i] = view.getUint32(chunk + i * 4, false);
    }
    
    // 扩展为80个字
    for (let i = 16; i < 80; i++) {
      w[i] = rotateLeft(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1);
    }
    
    // 初始化工作变量
    let a = h0;
    let b = h1;
    let c = h2;
    let d = h3;
    let e = h4;
    
    // 主循环
    for (let i = 0; i < 80; i++) {
      let f, k;
      if (i < 20) {
        f = (b & c) | ((~b) & d);
        k = 0x5A827999;
      } else if (i < 40) {
        f = b ^ c ^ d;
        k = 0x6ED9EBA1;
      } else if (i < 60) {
        f = (b & c) | (b & d) | (c & d);
        k = 0x8F1BBCDC;
      } else {
        f = b ^ c ^ d;
        k = 0xCA62C1D6;
      }
      
      const temp = (rotateLeft(a, 5) + f + e + k + w[i]) >>> 0;
      e = d;
      d = c;
      c = rotateLeft(b, 30);
      b = a;
      a = temp;
    }
    
    // 添加到哈希值
    h0 = (h0 + a) >>> 0;
    h1 = (h1 + b) >>> 0;
    h2 = (h2 + c) >>> 0;
    h3 = (h3 + d) >>> 0;
    h4 = (h4 + e) >>> 0;
  }
  
  // 生成最终哈希值
  const hash = new Uint8Array(20);
  const hashView = new DataView(hash.buffer);
  hashView.setUint32(0, h0, false);
  hashView.setUint32(4, h1, false);
  hashView.setUint32(8, h2, false);
  hashView.setUint32(12, h3, false);
  hashView.setUint32(16, h4, false);
  
  return hash;
}

/**
 * 左旋转函数
 */
function rotateLeft(value, amount) {
  return ((value << amount) | (value >>> (32 - amount))) >>> 0;
}

/**
 * 生成TOTP验证码（简化版本）
 */
export async function generateTOTP(secret, timestamp = Date.now(), options = {}) {
  const { interval = 30, digits = 6 } = options;

  try {
    // 1. 将 Base32 密钥解码为 Uint8Array
    const key = base32ToUint8Array(secret);

    // 2. 计算时间步长
    let timeStep = Math.floor(timestamp / (interval * 1000));

    // 3. 将时间步长转换为 8 字节的大端序 Uint8Array
    const timeArray = new Uint8Array(8);
    for (let i = 7; i >= 0; i--) {
      timeArray[i] = timeStep & 0xFF;
      timeStep >>= 8;
    }

    // 4. 计算 HMAC-SHA1
    const hmacDigest = hmacSha1(key, timeArray);

    // 5. 动态截断
    const offset = hmacDigest[hmacDigest.length - 1] & 0x0F;
    let code = (
      ((hmacDigest[offset] & 0x7F) << 24) |
      ((hmacDigest[offset + 1] & 0xFF) << 16) |
      ((hmacDigest[offset + 2] & 0xFF) << 8) |
      (hmacDigest[offset + 3] & 0xFF)
    );

    // 6. 取模得到指定位数的验证码
    code = code % Math.pow(10, digits);

    // 7. 格式化为指定长度的字符串
    return code.toString().padStart(digits, '0');
  } catch (error) {
    console.error('TOTP生成失败:', error);
    throw error;
  }
}
